﻿using CalligraphyWeb;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using ThuPhap.Models;
using System.Data.Entity;
using CalligraphyWeb.Models;

namespace Calligraphy.Models
{
    public class Item
    {
        #region Data Members
        private item data;
        public item Data
        {
            get
            {
                if (data == null)
                    data = new item();

                return data;
            }
            set
            {
                if (data == value) return;
                data = value;
            }
        }
        #endregion

        #region Class Methods
        public Item() {
            this.data = new item();
        }
        public Item(StoredItem sItem)
        {
            Get(sItem);
        }

        public Item(int id, bool isLazy = true)
        {
            Get(id, isLazy);
        }

        public Item(item obj)
        {
            Get(obj);
        }

        public Item(template template)
        {
            Get(template);
        }
        public Item Get(int id, bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var query = db.items.Where(c => c.id == id);
                if (!isLazy) query = query.Include(o => o.itemControls);
                
                if (query.Count() > 0)
                {
                    var obj = query.FirstOrDefault();
                    return Get(obj);
                }
                else
                    return null;
            }
        }

        public Item Get(item obj)
        {
            if (this.data == obj) return this;

            this.data = obj;
            return this;
        }

        public Item Get(StoredItem sItem)
        {
            if (sItem == null) return null;
            string bgDir = HttpRuntime.AppDomainAppPath + "\\Data\\Backgrounds\\";
            string exDir = HttpRuntime.AppDomainAppPath + "\\Data\\ItemImages\\";
            //save image files
            //background
            MemoryStream ms = new MemoryStream(sItem.Background);
            Image bgImg = Image.FromStream(ms);
            string bgFilename = "bg-" + Guid.NewGuid() + ".png";
            string bgFileDir = bgImg + bgFilename;
            bgImg.Save(bgFileDir, ImageFormat.Png);

            //exported image
            ms = new MemoryStream(sItem.Image);
            Image exImg = Image.FromStream(ms);
            string exFileName = "ex-" + Guid.NewGuid() + ".png";
            string exFileDir = exDir + exFileName;
            bgImg.Save(exFileName, ImageFormat.Png);

            this.data.background = bgFilename;
            this.data.preview = exFileName;
            this.data.width = sItem.BackgroundWidth;
            this.data.height = sItem.BackgroundHeight;
            this.data.x = 0;
            this.data.y = 0;
            this.data.status = "active";

            foreach (var ctrl in sItem.TextControl)
            {
                var temp = new itemControl(){
                    id = 0,
                    align = ctrl.Align,
                    C_left = ctrl.Left,
                    C_top = ctrl.Top,
                    fontFamily = ctrl.FontFamily,
                    fontSize = ctrl.FontSize,
                    isBold = ctrl.IsBold,
                    isItalic = ctrl.IsItalic,
                    isSelected = ctrl.IsSelected,
                    foreground = ctrl.Foreground,
                    height = ctrl.Height,
                    width = ctrl.Width,
                    text = ctrl.Text,
                    unicodeText = ctrl.UnicodeText,
                    type = ctrl.Type
                };
                this.data.itemControls.Add(temp);
            }

            return this;
        }

        public Item Get(template template)
        {
            string bgDir = HttpRuntime.AppDomainAppPath + "Data\\Backgrounds\\";
            string exDir = HttpRuntime.AppDomainAppPath + "Data\\ItemImages\\";
            string templateBackgroundDir = HttpRuntime.AppDomainAppPath + "Data\\TemplateBackgrounds\\";
            string TemplateImageDir = HttpRuntime.AppDomainAppPath + "Data\\TemplateImages\\";

            this.data = new item();

            //copy images
            string backgroundPath = "";
            double width = 480;
            double height = 800;
            if (File.Exists(templateBackgroundDir + template.image))
            {
                Image background = Image.FromFile(templateBackgroundDir + template.image); //background
                backgroundPath = bgDir + template.image;
                if (!File.Exists(backgroundPath))
                    background.Save(backgroundPath);
                width = background.Width;
                height = background.Height;
                this.data.background = template.image;
            }

            string thumbnailPath = "";
            if (File.Exists(TemplateImageDir + template.thumbnail))
            {
                Image thumbnail = Image.FromFile(TemplateImageDir + template.thumbnail);
                thumbnailPath = exDir + template.thumbnail;
                thumbnail.Save(thumbnailPath);

                this.data.preview = template.thumbnail;
            }
            
            
            //Converting
            this.data.id = 0;
            this.data.height = template.height;
            this.data.userid = template.userid;
            this.data.status = "active";
            this.data.width = width;
            this.data.height = height;
            this.data.x = 0;
            this.data.y = 0;
            this.data.created = DateTime.Now;
            this.data.updated = DateTime.Now;
            this.data.guid = Guid.NewGuid();

            //text controls
            foreach (var iter in template.templateControls)
            {
                ItemControl temp = new ItemControl(iter);
                this.data.itemControls.Add(temp.Data);
            }
            return this;
        }

        public ItemThumbnail ToThumbnail()
        {
            var result = new ItemThumbnail()
            {
                ID = this.data.id,
                Name = this.data.name,
                Date = this.data.updated.Value,
                Thumbnail = this.data.preview,
                UserID = this.data.userid.HasValue ? this.data.userid.Value : 0
            };
            if (this.data.userid.HasValue)
            {
                if (this.data.userid.Value > 0)
                {
                    var user = new User(this.data.userid.Value);
                    result.Username = user.Data.username;
                }
            }

            return result;
        }

        public template ToTemplate(string name, string description)
        {
            Template temp = new Template(name, description, this.data);
            return temp.Data;
        }

        public Template ToTemplateInterface(string name, string description)
        {
            Template temp = new Template(name, description, this.data);
            return temp;
        }

        public StoredItem ToStoredItem()
        {
            if (this.data == null)  return null;
            string bgDir = HttpRuntime.AppDomainAppPath + "Data\\Backgrounds\\";
            string exDir = HttpRuntime.AppDomainAppPath + "Data\\ItemImages\\";
            
            ImageConverter converter = new ImageConverter();
            Image background = null;
            Image preview = null;
            byte[] bgArray = null;
            byte[] previewArray = null;

            double width = 480;
            double height = 800;
            if (File.Exists(bgDir + data.background))
            {
                background = Image.FromFile(bgDir + data.background);
                bgArray = (byte[])converter.ConvertTo(background, typeof(byte[]));
                width = background.Width;
                height = background.Height;
            }

            if (File.Exists(exDir + data.preview))
            {
                preview = Image.FromFile(exDir + data.preview);
                previewArray = (byte[])converter.ConvertTo(preview, typeof(byte[]));

            }

            var result = new StoredItem() { 
                Name = data.name,
                Background = bgArray,
                BackgroundWidth = width,
                BackgroundHeight = height,
                Date = DateTime.Today,
                Image = previewArray,
                TextControl = new ObservableCollection<TextControlInfo>()
            };

            foreach (var iter in data.itemControls)
            {
                using (calligraphyEntities db = new calligraphyEntities()){
                     db.Configuration.LazyLoadingEnabled = true;
                    var ff = db.fontFamilies.SingleOrDefault(o => o.name == iter.fontFamily);
                    var color = ColorTranslator.FromHtml("#" + iter.foreground);

                    string foreground = color.A + "_" + color.R + "_" + color.G + "_" + color.B;
                    var temp = new TextControlInfo() { 
                        Align = iter.align.Value,
                        FontFamily = ff.phonePath,
                        FontSize = iter.fontSize.Value/0.8,
                        Foreground = foreground,
                        Height = iter.height.Value,
                        IsBold = iter.isBold.Value,
                        IsItalic = iter.isItalic.Value,
                        IsSelected = iter.isSelected.Value,
                        Left = iter.C_left.Value,
                        Top = iter.C_top.Value,
                        Text = iter.text,
                        UnicodeText = iter.unicodeText,
                        Type = iter.type.Value,
                        Width = iter.width.Value

                    };

                    result.TextControl.Add(temp);
                }
            }

            return result;
        }

        private int Insert()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.items.Add(data);
                
                //insert item controls
                foreach (var iter in data.itemControls)
                {
                    iter.itemID = data.id;
                    db.itemControls.Add(iter);
                }
                db.SaveChanges();
                return data.id;
            }
        }

        private int Update()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                var obj = db.items.SingleOrDefault(o => o.id == data.id);

                obj.background = data.background;
                obj.height = data.height;
                obj.preview = data.preview;
                obj.qrcode = data.qrcode;
                obj.status = data.status;
                obj.updated = DateTime.Now;
                obj.userid = data.userid;
                obj.width = data.width;
                obj.x = data.x;
                obj.y = data.y;

                db.items.Attach(obj);
                db.Entry(obj).State = System.Data.EntityState.Modified;
                //insert item controls
                ItemControl.DeleteByItem(data.id);
                foreach (var iter in data.itemControls)
                {
                    iter.itemID = obj.id;
                    db.itemControls.Add(iter);
                }
                db.SaveChanges();
                return data.id;
            }
        }

        public int Save()
        {
            if (data.id == 0)
                return Insert();
            else
                return Update();
        }

        public int Delete()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var obj = db.items.SingleOrDefault(o => o.id == data.id);
                var controls = from c in db.itemControls
                               where c.itemID == obj.id
                               select c;

                foreach (var iter in controls)
                    db.itemControls.Remove(iter);

                db.items.Remove(obj);
                db.SaveChanges();
                
            }
            return 1;
        }
        #endregion

        #region Static Methods
        public static ObservableCollection<item> Get(string sortColumn = "id", bool isAsc = false,
                                                    int pageIndex = 1, int pageSize = int.MaxValue,
                                                    bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = isLazy;
                IQueryable<item> query = db.items.AsQueryable();
                if (!isLazy) query.Include(o => o.itemControls);

                query = Sorting(query, sortColumn, isAsc);
                query = Paging(query, pageIndex, pageSize);

                if (query == null)
                    return new ObservableCollection<item>();
                else
                    return new ObservableCollection<item>(query.ToList());
            }
        }

        public static List<long> Save(Collection<item> collection)
        {
            var result = new List<long>();
            foreach (var obj in collection)
            {
                var temp = new Item(obj);
                result.Add(temp.Save());
            }

            return result;
        }

        public static int Delete(Collection<item> collection)
        {
            int result = 0;
            using (calligraphyEntities db = new calligraphyEntities())
            {
                foreach (var obj in collection)
                {
                    db.items.Remove(obj);
                    result++;
                }

                db.SaveChanges();
            }
            return result;
        }

        private static IQueryable<item> Sorting(IQueryable<item> query, string sortColumn = "id", bool isAsc = false)
        {
            switch (sortColumn)
            {
                case "background":
                    query = isAsc ? query.OrderBy(o => o.background) : query.OrderByDescending(o => o.background);
                    break;
                case "guid":
                    query = isAsc ? query.OrderBy(o => o.guid) : query.OrderByDescending(o => o.guid);
                    break;
                case "author":
                    query = isAsc ? query.OrderBy(o => o.userid) : query.OrderByDescending(o => o.userid);
                    break;
                case "status":
                    query = isAsc ? query.OrderBy(o => o.status) : query.OrderByDescending(o => o.status);
                    break;
                case "date":
                    query = isAsc ? query.OrderBy(o => o.created) : query.OrderByDescending(o => o.created);
                    break;
                case "update":
                    query = isAsc ? query.OrderBy(o => o.updated) : query.OrderByDescending(o => o.updated);
                    break;
                case "id":
                default:
                    query = isAsc ? query.OrderBy(o => o.id) : query.OrderByDescending(o => o.id);
                    break;
            }

            return query;
        }

        private static IQueryable<item> Paging(IQueryable<item> query, int pageIndex = 1, int pageSize = 10)
        {
            if (pageIndex <= 1)
                pageIndex = 0;
            else
                pageIndex--;

            return query.Skip(pageIndex * pageSize).Take(pageSize);
        }

        public static ObservableCollection<item> Search(string background = "", 
                                        int author = 0, string status = "",
                                        DateTime? createFrom = null, DateTime? createTo = null,
                                        DateTime? updateFrom = null, DateTime? updateTo = null,
                                        string sortColumn = "id", bool isAsc = false,
                                        int pageIndex = 1, int pageSize = 10,
                                        bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var query = from c in db.items
                            where (string.IsNullOrEmpty(background) ? true : c.background.ToLower().Contains(background.ToLower()))
                            && (string.IsNullOrEmpty(status) ? true : c.status.ToLower().Contains(status.ToLower()))
                            && (author == 0 ? true : c.userid == author)
                            && (createFrom == null ? true : createFrom.Value <= c.created)
                            && (createTo == null ? true : createTo.Value >= c.created)
                            && (updateFrom == null ? true : updateFrom.Value <= c.updated)
                            && (updateTo == null ? true : updateTo.Value >= c.updated)
                            select c;

                if (!isLazy) query = query.Include(o => o.itemControls);
                query = Sorting(query, sortColumn, isAsc);
                query = Paging(query, pageIndex, pageSize);

                if (query.Count() > 0)
                    return new ObservableCollection<item>(query.ToList());
                else
                    return new ObservableCollection<item>();
            }
        }
        #endregion
    }
}
